package marvin.webapp.audio.action;

import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedProperty;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import org.primefaces.model.DefaultTreeNode;

import marvin.webapp.audio.client.MarvinClient;
import marvin.webapp.audio.displaybeans.ClientDB;
import marvin.webapp.audio.displaybeans.FileTreeNode;
import marvin.webapp.audio.displaybeans.TreeBean;
import marvin.webapp.audio.displaybeans.URITreeNode;
import marvin.webapp.audio.subscription.ClientHandler;
import marvin.webapp.audio.subscription.SubscriptionServer;
import marvin.webapp.audio.util.MagicTool;
import marvin.webapp.common.action.AbstractWebAction;
import marvin.webapp.exception.MarvinException;

/**
 * Common class for any web action.
 *
 */
public abstract class AbstractAudioWebAction extends AbstractWebAction{
	
	private static final long serialVersionUID = 7057527719243346590L;
	public static final Integer SUBSCRIPTION_PORT = 4242;

	private static SubscriptionServer subServer;
	private List<ClientDB> clientDBs;
	protected ClientDB selectedClientDB;
	protected DefaultTreeNode selectedNode;
	protected File selectedResource;
	
	@ManagedProperty(value = "#{treeBean}")
	protected TreeBean treeBean;
	
	protected void startSubscriptionServer(){
		if(subServer == null){
			subServer = new SubscriptionServer(SUBSCRIPTION_PORT, treeBean);
			subServer.start();
			
			MarvinClient.startClient();
		}
	}
	
	public String getLoad(){
		clientDBs = new ArrayList<ClientDB>();
		
		for (ClientHandler c : subServer.getClients()) {
			clientDBs.add(new ClientDB(c));
		}
		
		return "";
	}
	
	public void refreshClientDBs() {
		List<ClientDB> newClientDBs = new ArrayList<ClientDB>();

		for (ClientHandler c : subServer.getClients()) {
			if (!alreadyContained(c))
				clientDBs.add(new ClientDB(c));

			newClientDBs.add(new ClientDB(c));
		}

		for (ClientDB db : new ArrayList<ClientDB>(clientDBs)) {
			if (!contained(db, newClientDBs))
				clientDBs.remove(db);
		}
	}
	
	private boolean alreadyContained(ClientHandler c) {
		for (ClientDB client : clientDBs) {
			if (c.getClientName() != null
					&& c.getClientName().equals(client.getName()))
				return true;
		}

		return false;
	}
	
	private boolean contained(ClientDB db, List<ClientDB> newClientDBs) {
		for (ClientDB dispBean : newClientDBs) {
			if (dispBean.getName() != null
					&& dispBean.getName().equals(db.getName()))
				return true;
		}
		return false;
	}
	
	public void streamFile(){
		selectedNode = treeBean.getSelectedNode();
		if(selectedClientDB != null){
			if(selectedNode != null){
				/*if(selectedNode instanceof FileTreeNode){
					FileTreeNode selectedFileNode = (FileTreeNode)selectedNode;
					if(selectedFileNode.getFile().isFile() || selectedFileNode.getFile().isDirectory() ){
						try {
							selectedClientDB.stream(selectedFileNode.getFile());
						} catch (IOException e) {
							e.printStackTrace();
							displayMessage(FacesMessage.SEVERITY_ERROR, "File streaming", e.getMessage());
						} catch (InterruptedException e) {
							e.printStackTrace();
							displayMessage(FacesMessage.SEVERITY_ERROR, "File streaming", e.getMessage());
						} catch (MarvinException e) {
							e.printStackTrace();
							displayMessage(FacesMessage.SEVERITY_ERROR, "File streaming", e.getMessage());
						}
					}
				} else*/ if (selectedNode instanceof URITreeNode){
					URITreeNode uriNode = (URITreeNode)selectedNode;
					if(uriNode.getUri() != null){
						try {
							selectedClientDB.stream(uriNode.getUri());
						} catch (IOException e) {
							e.printStackTrace();
						}
					}
				} else if (selectedClientDB.getPlayList() != null) {
					try{
						selectedClientDB.streamPlayList();
					} catch (IOException e) {
						displayMessage(FacesMessage.SEVERITY_ERROR, "File streaming", e.getMessage());
					} catch (MarvinException e) {
						displayMessage(FacesMessage.SEVERITY_ERROR, "File streaming", e.getMessage());
					}
				} else
					displayMessage(FacesMessage.SEVERITY_WARN, "File streaming", "Sorry I am only able to stream files.");
			} else {
				displayMessage(FacesMessage.SEVERITY_WARN, "File streaming", "Please select a file");				
			}
		} else {
			displayMessage(FacesMessage.SEVERITY_ERROR, "File streaming", "No client selected");
		}
	}
	
	public void suspendStream(){
		if(selectedClientDB != null){	
			//try {
				if(selectedClientDB.getClient().getSrv() != null){
					selectedClientDB.getClient().getSrv().suspendStreaming();
					selectedClientDB.setResumeVisible(true);
				}
			/*} catch (IOException e) {
				displayMessage(FacesMessage.SEVERITY_WARN, "Suspend streaming", e.getMessage());
				e.printStackTrace();
			}*/
		} else {
			displayMessage(FacesMessage.SEVERITY_ERROR, "File streaming", "No client selected");
		}
	}
	
	
	public void resumeStream(){
		if(selectedClientDB != null){	
			//try {
				if(selectedClientDB.getClient().getSrv() != null){
					selectedClientDB.getClient().getSrv().resumeStreaming();
					selectedClientDB.setResumeVisible(false);
				}
			/*} catch (IOException e) {
				displayMessage(FacesMessage.SEVERITY_WARN, "Resume streaming", e.getMessage());
				e.printStackTrace();
			}*/
		} else {
			displayMessage(FacesMessage.SEVERITY_ERROR, "File streaming", "No client selected");
		}
	}
	
	public void repeatStream(){
		if(selectedClientDB != null){
			selectedClientDB.getClient().getSrv().setRepeatMode(!selectedClientDB.getClient().getSrv().getRepeatMode());
		} else {
			displayMessage(FacesMessage.SEVERITY_ERROR, "Repeat streaming", "No client selected");
		}
	}
	
	public void shuffleStream(){
		if(selectedClientDB != null){
			selectedClientDB.getClient().getSrv().setShuffle(!selectedClientDB.getClient().getSrv().isShuffle());
		} else {
			displayMessage(FacesMessage.SEVERITY_ERROR, "Shuffle streaming", "No client selected");
		}
	}
	
	public void playNext(){
		if(selectedClientDB != null){
			try {
				if(selectedClientDB.getClient().getSrv() != null)
					selectedClientDB.getClient().getSrv().playNext();
			} catch (IOException e) {
				displayMessage(FacesMessage.SEVERITY_ERROR, "Next file", e.getMessage());
				e.printStackTrace();
			} catch (MarvinException e) {
				displayMessage(FacesMessage.SEVERITY_ERROR, "File streaming", e.getMessage());
				e.printStackTrace();
			}
		} else {
			displayMessage(FacesMessage.SEVERITY_ERROR, "File streaming", "No client selected");
		}
	}
	
	public void playPrevious(){
		if(selectedClientDB != null){
			try {
				if(selectedClientDB.getClient().getSrv() != null)
					selectedClientDB.getClient().getSrv().playPrevious();
			} catch (IOException e) {
				displayMessage(FacesMessage.SEVERITY_ERROR, "Next file", e.getMessage());
				e.printStackTrace();
			} catch (MarvinException e) {
				displayMessage(FacesMessage.SEVERITY_ERROR, "File streaming", e.getMessage());
				e.printStackTrace();
			}
		} else {
			displayMessage(FacesMessage.SEVERITY_ERROR, "File streaming", "No client selected");
		}
	}
	
	public void stopStream(){
		if(selectedClientDB != null){	
			//try {
				if(selectedClientDB.getClient().getSrv() != null)
					selectedClientDB.getClient().getSrv().stopStreaming();
			/*} catch (IOException e) {
				displayMessage(FacesMessage.SEVERITY_WARN, "Stop streaming", e.getMessage());
				e.printStackTrace();
			}*/
		} else {
			System.out.println("selectedClientDB is null");
		}
	}
	
	public void addToPlayList() {
		if (selectedClientDB != null) {
			selectedNode = treeBean.getSelectedNode();
			if (selectedNode != null) {
				if (selectedNode instanceof FileTreeNode) {
					FileTreeNode tNode = (FileTreeNode) selectedNode;
					if(tNode.getFile() != null && tNode.getFile().isDirectory()){
						List<File> children = MagicTool.getOnlyFiles(tNode.getFile());
						selectedClientDB.getPlayList().addAll(children);
					}
					else if(tNode.getFile() != null && tNode.getFile().getAbsolutePath().endsWith(".mp3")){
						selectedClientDB.getPlayList().add(tNode.getFile());
					} else if(tNode.getFile() != null && tNode.getFile().getAbsolutePath().endsWith(".avi")){
						selectedClientDB.getPlayList().add(tNode.getFile());
					}
				} else
					displayMessage(FacesMessage.SEVERITY_WARN,
							"File streaming",
							"Sorry I am only able to add files to play list.");
			} else {
				displayMessage(FacesMessage.SEVERITY_WARN, "File streaming",
						"Please select a file");
			}
		} else {
			displayMessage(FacesMessage.SEVERITY_ERROR, "File streaming",
					"No client selected");
		}
	}
	
	public void removeSelectedResource(){
		if(selectedClientDB != null && selectedResource != null){
			selectedClientDB.getPlayList().remove(selectedResource);
		}
	}
	
	public void emptyPlayList(){
		if(selectedClientDB != null){
			selectedClientDB.getPlayList().clear();
		}
	}
	
	public void playSelectedResource(){
		if(selectedClientDB != null && selectedResource != null){
			try {
				selectedClientDB.stream(selectedResource);
			} catch (IOException e) {
				displayMessage(FacesMessage.SEVERITY_ERROR, "File streaming", e.getMessage());
			} catch (InterruptedException e) {
				displayMessage(FacesMessage.SEVERITY_ERROR, "File streaming", e.getMessage());
			} catch (MarvinException e) {
				displayMessage(FacesMessage.SEVERITY_ERROR, "File streaming", e.getMessage());
			}
		}
	}

	public TreeBean getTreeBean() {
		return treeBean;
	}

	public void setTreeBean(TreeBean treeBean) {
		this.treeBean = treeBean;
	}
	
	public List<ClientDB> getClientDBs() {
		return clientDBs;
	}

	public SubscriptionServer getServer() {
		return subServer;
	}

	public ClientDB getSelectedClientDB() {
		return selectedClientDB;
	}

	public void setSelectedClientDB(ClientDB selectedClientDB) {
		this.selectedClientDB = selectedClientDB;
	}

	public File getSelectedResource() {
		return selectedResource;
	}

	public void setSelectedResource(File selectedResource) {
		this.selectedResource = selectedResource;
	}
}
